package com.bosc.modeling.controller;

import com.bosc.modeling.common.BaseController;
import com.bosc.modeling.common.ResponseFactory;
import com.bosc.modeling.pojo.gen.CompetitionEntity;
import com.bosc.modeling.service.CompetitionService;
import com.bosc.modeling.utils.FileHandleUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.*;

@RestController
public class CompetitionController extends BaseController {
    @Autowired
    CompetitionService competitionService;
    @Autowired
    ThreadPoolTaskScheduler threadPoolTaskScheduler;
    @Bean
    public ThreadPoolTaskScheduler threadPoolTaskScheduler(){
        return new ThreadPoolTaskScheduler();
    }
    private class CompetitionStateUpdateScheduler implements Runnable{
        private String competitionId;
        private CompetitionService competitionService;
        public CompetitionStateUpdateScheduler(CompetitionService competitionService,String competitionId){
           this.competitionService = competitionService;
           this.competitionId = competitionId;
        }
        @Override
        public void run() {
            List<CompetitionEntity> competitions = competitionService.getCompetitionById(competitionId);
            if(competitions != null && competitions.size() == 1){
                CompetitionEntity competition = competitions.get(0);
                long start_time =competition.getStartTime().getTime();
                long end_time_A =competition.getEndTimeA().getTime();
                long end_time_B =competition.getEndTimeB().getTime();
                short state = getState(start_time,end_time_A,end_time_B);
                competition.setState(state);
                competitionService.updateCompetition(competition);
                log.info("competition:"+competition.getCompetitionName()+" update state:"+state);
            }
        }
        private short getState(long start_time,long end_time_A,long end_time_B){
            long cur = new Date().getTime();
            short state = 0;
            if(cur < start_time){
                state = 0;
                return state;
            }
            if(cur >= start_time && cur <= end_time_A){
                state = 1;
                return state;
            }
            if(cur > end_time_A && cur <= end_time_B){
                state = 2;
                return state;
            }
            if(cur > end_time_A){
                state = 3;
                return state;
            }
            return 0;
        }
    }

    @RequestMapping(value = "/competition_list", method = RequestMethod.GET)
    Object getCompetitionList(@RequestParam("page") int page, @RequestParam("limit") int limit) throws Exception {
       log.info("getCompetitionList:page="+page+",limit="+limit);
        try {
            PageHelper.startPage(page, limit);
            List<CompetitionEntity> list = competitionService.getCompetitionList();
            PageInfo<CompetitionEntity> pageInfo = new PageInfo<CompetitionEntity>(list);
            long count = pageInfo.getTotal();
            List data = pageInfo.getList();
            HashMap res = new HashMap();
            res.put("status",0);
            res.put("message","");
            res.put("total",count);
            res.put("data", data);
            return res;
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
    }
    @RequestMapping(value = "/competition_del", method = RequestMethod.POST)
    Object delCompetition(@RequestBody String body) throws Exception {
        log.info("delCompetition");
        try {
            JSONObject data = new JSONObject(body);
            JSONArray arr = data.getJSONArray("ids");

            for (int i = 0; i < arr.length(); i++) {
                int id = arr.getInt(i);
                CompetitionEntity competition = competitionService.getCompetition(id);
                String trainDataUrl = competition.getTrainDataUrl();
                String testDataUrlA = competition.getTestDataUrlA();
                String testDataUrlB = competition.getTestDataUrlB();
                FileUtils.deleteDirectory(new File(getDelPath(trainDataUrl)));
                FileUtils.deleteDirectory(new File(getDelPath(testDataUrlA)));
                FileUtils.deleteDirectory(new File(getDelPath(testDataUrlB)));
                competitionService.delCompetition(id);
            }
            return ResponseFactory.successResponse(null);

        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
    }
    @RequestMapping(value = "/get_competition_by_id", method = RequestMethod.POST)
    Object getCompetitionById(@RequestBody String body) throws Exception {
        log.info("getCompetitionById");
        try {
            JSONObject data = new JSONObject(body);
            String competitionId = data.getString("competition_id");
            List<CompetitionEntity> competitions = competitionService.getCompetitionById(competitionId);
            if (competitions != null && competitions.size() == 1){
                CompetitionEntity competition = competitions.get(0);
                competition.setJoins((int)competitionService.getJoins(competition.getCompetitionId()));
                return ResponseFactory.successResponse(competition);
            }else {
                return ResponseFactory.failureResponse("1","该竞赛记录不存在");
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
    }
    String getDelPath(String fileUrl){
        String[] tmps = fileUrl.split("/");
        int len = tmps.length;
        return uploadFolder+tmps[len-2];
    }
    @RequestMapping(value = "/search_competition", method = RequestMethod.GET)
    Object searchCompetition(@RequestParam("page") int page, @RequestParam("limit") int limit, @RequestParam(defaultValue = "", value = "comp_name") String comp_name) throws Exception {
        log.info("searchCompetition:page="+page+",limit="+limit+",comp_name="+comp_name);
        try {
            PageHelper.startPage(page, limit);
            List<CompetitionEntity> list = competitionService.searchCompetition(comp_name);
            PageInfo<CompetitionEntity> pageInfo = new PageInfo<CompetitionEntity>(list);
            long count = pageInfo.getTotal();
            List data = pageInfo.getList();
            HashMap res = new HashMap();
            res.put("status",0);
            res.put("message","");
            res.put("total",count);
            res.put("data", data);
            return res;
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
    }
    @RequestMapping(value = "/add_competition", method = RequestMethod.POST)
    Object addCompetition(@RequestBody String body) throws Exception {
        log.info("addCompetition:"+body);
        try {
            JSONObject request = new JSONObject(body);
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String competition_name = request.getString("competition_name");
            String competition_desc = request.getString("competition_desc");
            String data_desc = request.getString("data_desc");
            long start_time = request.getLong("start_time");
            long end_time_A = request.getLong("end_time_A");
            long end_time_B = request.getLong("end_time_B");
            String train_data_url = request.getString("train_data_url");
            String test_data_url_A = request.getString("test_data_url_A");
            String test_data_url_B = request.getString("test_data_url_B");
            String owner = request.getString("owner");
            String creator = request.getString("creator");
            String evaluation = request.getString("evaluation");
            double ratio_A = request.getDouble("ratio_A");
            double ratio_B = request.getDouble("ratio_B");
            CompetitionEntity competition = new CompetitionEntity();
            competition.setCompetitionId(UUID.randomUUID().toString());
            competition.setCompetitionName(competition_name);
            competition.setCompetitionDesc(competition_desc);
            competition.setDataDesc(data_desc);
            competition.setStartTime(new Date(start_time));
            competition.setEndTimeA(new Date(end_time_A));
            competition.setEndTimeB(new Date(end_time_B));
            competition.setTrainDataUrl(train_data_url);
            competition.setTestDataUrlA(test_data_url_A);
            competition.setTestDataUrlB(test_data_url_B);
            competition.setCreateTime(new Date());
            competition.setState(getState(start_time,end_time_A,end_time_B));
            competition.setOwner(owner);
            competition.setCreator(creator);
            competition.setEvaluation(evaluation);
            competition.setRatioA(ratio_A);
            competition.setRatioB(ratio_B);
            competitionService.addCompetition(competition);
            threadPoolTaskScheduler.schedule(new CompetitionStateUpdateScheduler(competitionService, competition.getCompetitionId()), new Date(start_time));
            threadPoolTaskScheduler.schedule(new CompetitionStateUpdateScheduler(competitionService, competition.getCompetitionId()), new Date(end_time_A));
            threadPoolTaskScheduler.schedule(new CompetitionStateUpdateScheduler(competitionService, competition.getCompetitionId()), new Date(end_time_B));
            return ResponseFactory.successResponse(null);
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }

    }
    private String getCronStr(long time){
//        Date date = new Date(time);
        Calendar date = Calendar.getInstance();
        date.setTime(new Date(time));
        int second = date.get(Calendar.SECOND);
        int minute = date.get(Calendar.MINUTE);
        int hour = date.get(Calendar.HOUR_OF_DAY);
        int day = date.get(Calendar.DAY_OF_MONTH);
        int month = date.get(Calendar.MONTH)+1;
        int year = date.get(Calendar.YEAR);
        String cron = second+" "+minute+" "+hour+" "+day+" "+month+" ?";
        log.info(cron);
        return cron;
    }
    private short getState(long start_time,long end_time_A,long end_time_B){
        long cur = new Date().getTime();
        short state = 0;
        if(cur < start_time){
            state = 0;
            return state;
        }
        if(cur >= start_time && cur <= end_time_A){
            state = 1;
            return state;
        }
        if(cur > end_time_A && cur <= end_time_B){
            state = 2;
            return state;
        }
        if(cur > end_time_A){
            state = 3;
            return state;
        }
        return 0;
    }
    @RequestMapping(value = "/update_competition", method = RequestMethod.POST)
    Object updateCompetition(@RequestBody String body) throws Exception {
        log.info("updateCompetition:"+body);
//        System.out.println(body);
        try {
            JSONObject request = new JSONObject(body);
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String competition_name = request.getString("competition_name");
            String competition_desc = request.getString("competition_desc");
            String data_desc = request.getString("data_desc");
            long start_time = request.getLong("start_time");
            long end_time_A = request.getLong("end_time_A");
            long end_time_B = request.getLong("end_time_B");
            CompetitionEntity competition = competitionService.getCompetition(request.getInt("id"));
            competition.setCompetitionName(competition_name);
            competition.setCompetitionDesc(competition_desc);
            competition.setDataDesc(data_desc);
            if (competition.getStartTime().getTime() != start_time){
                threadPoolTaskScheduler.schedule(new CompetitionStateUpdateScheduler(competitionService, competition.getCompetitionId()), new Date(start_time));
            }
            if (competition.getEndTimeA().getTime() != end_time_A){
                threadPoolTaskScheduler.schedule(new CompetitionStateUpdateScheduler(competitionService, competition.getCompetitionId()), new Date(end_time_A));
            }
            if (competition.getEndTimeB().getTime() != end_time_B){
                threadPoolTaskScheduler.schedule(new CompetitionStateUpdateScheduler(competitionService, competition.getCompetitionId()), new Date(end_time_B));
            }
            competition.setStartTime(new Date(start_time));
            competition.setEndTimeA(new Date(end_time_A));
            competition.setEndTimeB(new Date(end_time_B));
            competition.setState(getState(start_time,end_time_A,end_time_B));
            if (request.has("train_data_url")){
                FileUtils.deleteDirectory(new File(getDelPath(competition.getTrainDataUrl())));
                competition.setTrainDataUrl(request.getString("train_data_url"));
            }
            if (request.has("test_data_url_A")){
                FileUtils.deleteDirectory(new File(getDelPath(competition.getTestDataUrlA())));
                competition.setTestDataUrlA(request.getString("test_data_url_A"));
            }
            if (request.has("test_data_url_B")){
                FileUtils.deleteDirectory(new File(getDelPath(competition.getTestDataUrlB())));
                competition.setTestDataUrlB(request.getString("test_data_url_B"));
            }

            competitionService.updateCompetition(competition);
            return ResponseFactory.successResponse(null);
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }

    }

    @Value("${file.uploadFolder}")
    private String uploadFolder;

    @Value("${file.uri}")
    private String uri;
    @RequestMapping(value = "/file_upload", method = RequestMethod.POST)
    Object trainFileUplpad(HttpServletRequest request, @RequestParam("file") MultipartFile file) throws Exception {
        log.info("upload:"+file.getOriginalFilename());
        try {
            long currentTime = System.currentTimeMillis();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
            String date = sdf.format(new Date(currentTime));
            String fileName = file.getOriginalFilename();
//            String fileName = FilenameUtils.getBaseName(originalFilename) + "-" + date + "." + FilenameUtils.getExtension(originalFilename);
            FileHandleUtil.upload(file.getInputStream(), uploadFolder + date + "/", fileName);
            String url = FileHandleUtil.getServerIPPort(request) + "/" + uri + date + "/" + fileName;
            HashMap data = new HashMap();
            data.put("url",url);
            return ResponseFactory.successResponse(data);
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }

    }
}
